# coding: utf-8

from django.http import HttpResponseRedirect, HttpResponse
from djangoext.mako import render_to_response , render_to_string, render_string

import time, datetime
import re
import cStringIO
import os
import random
import types, operator
from shangjie.utils import log, cache
from shangjie.utils import lunar

from shangjie.conf import settings
from sqlalchemy.sql import *

from functools import partial

from pyExcelerator import *

import random
import datetime, time
from contextlib import contextmanager
from collections import OrderedDict
from django.http import HttpResponse
from aliyunsdkdysmsapi.request.v20170525 import SendSmsRequest
from aliyunsdkdysmsapi.request.v20170525 import QuerySendDetailsRequest
from aliyunsdkcore.client import AcsClient
try:
    from aliyunsdkcore.profile import region_provider
except:
    pass
import uuid
import hashlib
import requests
import simplejson
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import sys
import urllib
import hashlib
import os

try:
    import uuid
except:
    import fake_uuid as uuid

import copy
from djangoext.urls import expose
from oa.utils import *

from oaconf import LOGDIR

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from oa.api.log import LOG

obj = LOG( name = 'viewsinfo' ,logdir = LOGDIR )
log = obj.init_logger()

def test( req ):
    # 公司信息表
    se = settings.DB_SESSION()
    content = {}
    content['profile'] = '1'
    content = {"pageNum":1,"pageSize":100,"size":1,"startRow":1,"endRow":1,"total":1,"pages":1,"list":[{"id":"PCID2016042300136147","name":"日照百嘉物业服务有限公司"}],"firstPage":1,"prePage":0,"nextPage":0,"lastPage":1,"isFirstPage":True,"isLastPage":True,"hasPreviousPage":False,"hasNextPage":False,"navigatePages":8,"navigatepageNums":[1]}
    return HttpResponse( sjapi.jsondumps( content , ensure_ascii = False , encoding = 'utf-8' ), content_type='application/json; charset=utf-8' )


class cryptaes():
    def __init__(self, key):
        self.key = key
        self.mode = AES.MODE_ECB

    # 加密函数，如果text不足16位就用空格补足为16位，
    # 如果大于16当时不是16的倍数，那就补足为16的倍数。
    def encrypt(self, text):
        cryptor = AES.new(self.key, self.mode)
        # 这里密钥key 长度必须为16（AES-128）,
        # 24（AES-192）,或者32 （AES-256）Bytes 长度
        # 目前AES-128 足够目前使用
        length = 16
        count = len(text)
        if count < length:
            add = (length - count)
            # \0 backspace
            text = text + ('\05' * add)
        elif count > length:
            add = (length - (count % length))
            text = text + ('\05' * add)
        self.ciphertext = cryptor.encrypt(text)
        # 因为AES加密时候得到的字符串不一定是ascii字符集的，输出到终端或者保存时候可能存在问题
        # 所以这里统一把加密后的字符串转化为16进制字符串
        return b2a_hex(self.ciphertext)

    # 解密后，去掉补足的空格用strip() 去掉
    def decrypt(self, text):
        cryptor = AES.new(self.key, self.mode)
        plain_text = cryptor.decrypt(a2b_hex(text))
        return plain_text.rstrip('\05')


def check_valid(code, crttime, mins=3):
    """ 校验code是否过期 """
    if not (code and crttime):
        return False, "验证内容和生成时间不可为空!"
    if mins == -1:
        # -1表示无限制
        return True, 'OK'

    dqsj = datetime.datetime.now()
    sjc = (dqsj - datetime.datetime.strptime(crttime, "%Y%m%d%H%M%S")).seconds
    # 有效时间差，单位：秒
    yxfs = int(mins)
    if sjc > 60 * yxfs:
        return False, ('[%s]已过期！' % code.encode('utf8'))
    else:
        return True, 'OK'

def get_uuid():
    return str( uuid.uuid4() )

def send_message( business_id, phonenum, sign_name, templatename, templateparams = None ):
    se = settings.DB_SESSION()
    REGION,AcessKeyId,AcessKeySecret = 'cn-hangzhou', '', ''
    PRODUCT_NAME = "Dysmsapi"
    DOMAIN = "dysmsapi.aliyuncs.com"
    # 获取AcessKeyId 和 AcessKeySecret
    params_sql = """select * from api_parameter where paramcode='AcessKeyId' or paramcode='AcessKeySecret'"""
    parames = se.execute(params_sql.decode('utf-8')).fetchall()
    for obj in parames:
        if obj.paramcode == 'AcessKeyId':AcessKeyId = obj.paramvalue.encode('utf8')
        if obj.paramcode == 'AcessKeySecret': AcessKeySecret=obj.paramvalue.encode('utf8')
    if not ( AcessKeySecret and AcessKeyId ):
        return False, '短信密钥未定义！'
    acs_client = AcsClient(AcessKeyId, AcessKeySecret, REGION)
    try:
        region_provider.modify_point(PRODUCT_NAME, REGION, DOMAIN)
    except:
        pass
    try:
        smsRequest = SendSmsRequest.SendSmsRequest()
        # 申请的短信模板编码
        smsRequest.set_TemplateCode(templatename)
        # 模板传参，参数为json对象
        if templateparams is not None:
            smsRequest.set_TemplateParam(templateparams)
        # 设置业务请求流水号，必填。
        smsRequest.set_OutId( business_id )
        # 短信签名
        smsRequest.set_SignName(sign_name)
        # 短信发送的号码。支持以逗号分隔的形式批量调用，上限为1000个手机号码。
        smsRequest.set_PhoneNumbers(phonenum)
        # 发送请求
        smsResponse = acs_client.do_action_with_exception(smsRequest)
        rest = eval(smsResponse)
        code, msg = rest.get('Code'), rest.get('Message')
        se.close()
        return True if code == 'OK' else False, "成功"  if code == 'OK' else msg
        #return smsResponse
    except Exception as e:
        # log.info('send message erro is %s' % e)
        return False , "短信发送异常！"

def send_messages( req ):
    """发送短信验证码API"""
    se = settings.DB_SESSION()
    # 获取请求对象
    flag, reqobj = get_reqobj(req)
    if not flag:
        return HttpResponse(sjapi.jsondumps({'rspcode': 8004, 'rspinfo': reqobj}, ensure_ascii=False, encoding='utf-8'),
                            content_type='application/json; charset=utf-8')

    # 初始化反馈信息
    rspcode, rspinfo, checkcode = 0, 'OK', ''
    try:
        # ③-获取请求要素，手机号码需解密获取
        log.info("发送短信验证码API请求内容: {0}".format(repr(reqobj)))
        phonenum = reqobj.get('strPhone', '')
        encrycode = reqobj.get('strCode', '')
        type = reqobj.get('strType', '0')

        try:
            aeskey_sql = """select paramvalue from api_parameter where paramcode='AESKEY'"""
            aeskey = se.execute(aeskey_sql.decode('utf-8')).fetchone()
            aesobj = cryptaes(str(aeskey.paramvalue))
            phonenum_1 = aesobj.decrypt(str(encrycode))
            log.info("解密后的手机号码为【{0}】".format(phonenum_1))
            if phonenum != phonenum_1:
                return HttpResponse(
                    sjapi.jsondumps({'rspcode': 8005, 'rspinfo': '手机号码验证不一致！'}, ensure_ascii=False, encoding='utf-8'),
                    content_type='application/json; charset=utf-8')
        except Exception as e:
            log.info('****** mesg erro %s' % e)
            return HttpResponse(
                sjapi.jsondumps({'rspcode': 8999, 'rspinfo': '服务器无响应，请稍候再试！'}, ensure_ascii=False, encoding='utf-8'),
                content_type='application/json; charset=utf-8')

        # ④-生成短信验证码
        if not phonenum or not phonenum.isdigit() or len(phonenum) < 11:
            return HttpResponse(
                sjapi.jsondumps({'rspcode': 8005, 'rspinfo': '手机号码非法！'}, ensure_ascii=False, encoding='utf-8'),
                content_type='application/json; charset=utf-8')
        # ④.1-判断手机号码是否已申请验证码及验证码是否已到期
        code_sql = """select id, checkcode, applytime from api_checkcode where phonenum='%s' and status='0' order by applytime desc""" % phonenum
        result = se.execute(code_sql.decode('utf-8')).fetchone()
        dqsj = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        if result:
            cid, checkcode, applytime = result.id, result.checkcode, result.applytime
            # ④.1.1-已申请未使用验证码，检查验证码是否已过期
            params_sql = """select paramvalue from api_parameter where paramcode='CheckCodeTimeout'"""
            validtime = se.execute(params_sql.decode('utf-8')).fetchone().paramvalue
            ret, msg = check_valid(checkcode, applytime, int(validtime))
            if ret == True:
                # ④.1.2-未超过有效期，重新发送验证码，验证码不变，更新生成时间
                checkcode_update = """update api_checkcode set applytime='%s' where id='%s'""" % (dqsj, cid)
                se.execute(checkcode_update.decode('utf-8'))
            else:
                # ④.1.3-超过有效期 需重新生成验证码
                checkcode = ''
                for i in range(6):
                    checkcode += str(random.randrange(0, 10))
                checkcode_update = """update api_checkcode set checkcode='%s', applytime='%s' where id='%s'""" % (checkcode, dqsj, cid)
                se.execute(checkcode_update.decode('utf-8'))
        else:
            # ④.1.4-初次申请，需生成验证码，并登记数据库表
            checkcode = ''
            for i in range(6):
                checkcode += str(random.randrange(0, 10))
            checkcode_insert = """insert into api_checkcode(checkcode, phonenum, status, applytime) values ('%s', '%s', '0', '%s')""" % (checkcode, phonenum, dqsj)
            se.execute(checkcode_insert.decode('utf-8'))

        # ⑤-调用短信发送API接口，发送短信
        params = simplejson.dumps({'code': checkcode}, ensure_ascii=False)
        # ----屏蔽实际短信，生产需放开（TODO）----
        params_sql = """select * from api_parameter where paramcode='MessageSign'"""
        MessageSign = se.execute(params_sql.decode('utf-8')).fetchone().paramvalue
        if type == '0':
            messageType = 'MessageMako'
        elif type == '1':
            messageType = 'MessageMako_Setpsw'
        elif type == '2':
            messageType = 'MessageMako_Unbind'
        elif type == '3':
            messageType = 'MessageMako_Cancel'
        params_sql = """select * from api_parameter where paramcode='%s'""" % messageType
        MessageMako = se.execute(params_sql.decode('utf-8')).fetchone().paramvalue
        ret, msg = send_message(get_uuid(), phonenum.encode('utf8'), MessageSign.encode('utf8'), MessageMako, params)
        # ret, msg = True, ''
        # ----------------------------------------
        if ret == False:
            rspcode, rspinfo = 8999, msg

        se.close()
        paramdict = {'rspcode': rspcode, 'rspinfo': rspinfo, 'checkcode': checkcode}
        return HttpResponse(
            sjapi.jsondumps(paramdict, ensure_ascii=False, encoding='utf-8'),
            content_type='application/json; charset=utf-8')
    except Exception as e:
        se.close()
        log.info('**** send erro %s' % e)
        # log.exception("方法[messages]异常！")
        rspcode, rspinfo = 8999, '请求处理异常！'
        return HttpResponse(
            sjapi.jsondumps(paramdict, ensure_ascii=False, encoding='utf-8'),
            content_type='application/json; charset=utf-8')
